using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Barrage.Global;
using System.Drawing;
using System.Drawing.Imaging;
using Spacedash.Logic.Scenario.Cells;
using SlimDX;

namespace Spacedash.Logic.Scenario
{
    /// <summary>
    /// BitmapScenarioLoader loads a scenario from a little XML file containing color/pattern information.
    /// It loads a bitmap file with colors that define cell data (for example, red pixels are obstacles)
    /// </summary>
    public abstract class BitmapScenarioLoader
    {
        const string XML_SCENARIO_ROOT = "scenario";
        const string XML_BITMAP_ATTRIBUTE = "bitmap";
        //const string XML_ROW_ELEMENT = "row";
        const string XML_NAME_ATTRIBUTE = "name";
        const string XML_COLOR_ATTRIBUTE = "color";
        //const string XML_COLNUMBER_ATTRIBUTE = "colnumber";
        //const string XML_COLUMN_ATTRIBUTE = "column";
        const string XML_CELLS_ELEMENT = "cells";
        const string XML_CELL_ELEMENT = "cell";
        const string XML_TYPE_ATTRIBUTE = "type";
        const string XML_GRIDLENGTH_ATTRIBUTE = "gridLength";

        /// <summary>
        /// Loads the scenario from the specified file
        /// </summary>
        /// <param name="file">XML file path</param>
        /// <returns>The loaded scenario</returns>
        public static Scenario LoadScenario(string file)
        {
            XmlDocument xd = new XmlDocument();
            Scenario scenario = null;
            try
            {
                xd.Load(file);
                foreach (XmlNode n in xd.ChildNodes)
                {
                    if (n.Name == XML_SCENARIO_ROOT)
                    {
                        if (scenario != null) throw new Exception("A scenario was already loaded");
                        scenario = loadScenarioData(n);
                    }
                }
            }
            catch (Exception e)
            {
                throw new System.Exception("Error parsing scenario " + file + ":\n" + e.Message, e);
            }
            return scenario;
        }

         static Scenario loadScenarioData(XmlNode xn)
        {
            Dictionary<Color4, CellData> cellData=new Dictionary<Color4,CellData>();
            // Load Color Definitions
            foreach (XmlNode xno in xn.ChildNodes)
            {
                if (xno.Name == XML_CELLS_ELEMENT)
                {
                    foreach (XmlNode xnod in xno.ChildNodes)
                    {
                        if (xnod.Name == XML_CELL_ELEMENT)
                            cellData.Add(XmlHelper.ParseXMLColorAttribute(xnod,XML_COLOR_ATTRIBUTE),CellManager.CellData[XmlHelper.GetXMLAttribute(xnod, XML_TYPE_ATTRIBUTE)]);
                    }
                }
            }

            // Load image
            string imageFile = XmlHelper.GetXMLAttribute(xn, XML_BITMAP_ATTRIBUTE);
            Bitmap b = new Bitmap(Scenario.SCENARIO_DIR+imageFile);
            BitmapData bd = b.LockBits(new Rectangle(0,0,b.Width,b.Height), System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
            int gridLength = XmlHelper.ParseXMLIntAttribute(xn, XML_GRIDLENGTH_ATTRIBUTE);
            Color3 scenarioColor = ((Color3)XmlHelper.ParseXMLColorAttribute(xn, XML_COLOR_ATTRIBUTE,GameMath.RandomColor()));
            Scenario scenario = new Scenario(XmlHelper.GetXMLAttribute(xn, XML_NAME_ATTRIBUTE), b.Width, b.Height, gridLength, scenarioColor);

            // Skip the grid rows
            int iRow = scenario.GridLength;
            unsafe
            {
                int* imgPtr = (int*)(bd.Scan0);
                for (int i = 0; i < bd.Width; i++)
                {
                    for (int j = 0; j < bd.Height; j++)
                    {
                        imgPtr = (int*)(bd.Scan0) + j * bd.Width + i;
                        int val = *imgPtr&0x00FFFFFF;
                        CellData cd=null;
                        if (cellData.TryGetValue(new Color4(val), out cd))
                            scenario.CellAt(iRow, j).CellData = cd;
                    }
                    iRow++;
                }
            }
            b.UnlockBits(bd);
            
            return scenario;
        }

    }

}
